/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.inspur.edp.lcm.metadata.core.manager;

import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataPackage;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.MetadataInfoInMavenWithProcessMode;
import com.inspur.edp.lcm.metadata.api.mvnEntity.withprocessmode.PackageWithMetadataInfoWithProcessMode;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.MavenUtils;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.core.GspProjectCoreService;
import com.inspur.edp.lcm.metadata.core.MavenUtilsCore;
import com.inspur.edp.lcm.metadata.core.MetadataCoreManager;
import com.inspur.edp.lcm.metadata.core.MetadataProjectCoreService;
import com.inspur.edp.lcm.metadata.core.persistence.RepositoryFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

public class MavenDeploymentForMdpkgManager extends MavenDeploymentManager {
    private MavenUtilsCore mavenUtilsCore = new MavenUtilsCore();

    private FileServiceImp fileServiceImp = new FileServiceImp();

    private MetadataProjectCoreService metadataProjectCoreService = new MetadataProjectCoreService();

    private GspProjectCoreService gspProjectCoreService = new GspProjectCoreService();

    private RestTemplate restTemplate = new RestTemplate();

    private PomManager pomManager = new PomManager();

    private String projPath;
    private String repoId;
    private String version;
    private String dependencyVersion;
    private String mavenPath;
    private String metadataBinPath;
    private String metadataTempDir;
    private String metadataPomPath;
    private String mdpkgPath;
    private Model sourceModel;

    public MavenDeploymentForMdpkgManager() {

    }

    public void deploy(String projPath, String repoId, String version, String dependencyVersion, String mavenPath) {
        this.projPath = projPath;
        this.repoId = repoId;
        this.version = version;
        this.dependencyVersion = dependencyVersion;
        this.mavenPath = mavenPath;
        metadataBinPath = projPath + File.separator + "metadata" + File.separator + "bin";
        metadataTempDir = fileServiceImp.getCombinePath(projPath + File.separator + "metadata", MavenUtils.TEMP_FOLDER);
        metadataPomPath = fileServiceImp.getCombinePath(metadataTempDir, MavenUtils.POM_FILE);

        beforeDeploy();

        doDeploy();

        afterDeploy();
    }

    @Override
    protected void beforeDeploy() {
        handlePomForMetadata();
    }

    @Override
    protected void doDeploy() {
        try {
            if (!mavenUtilsCore.exeMavenCommand(metadataTempDir, mavenPath, "deploy")) {
                throw new RuntimeException("部署元数据包失败");
            }
        } catch (Exception e) {
            throw new RuntimeException("部署元数据失败", e);
        } finally {
            try {
                fileServiceImp.deleteAllFilesUnderDirectory(metadataTempDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void afterDeploy() {
        String metadaPackageName = new File(mdpkgPath).getName();
        String repoUrl = RepositoryFactory.getInstance().getMavenSettingsRepository().getRepoUrl(repoId);
        String processMode = metadataProjectCoreService.getProcessMode(projPath).toString();
        updateMetadataIndex(metadaPackageName, metadataBinPath, repoUrl, sourceModel, processMode);
    }

    private void handlePomForMetadata() {
        // 准备pom
        pomManager.createPomWithSourceModel(createSourceModel(), metadataPomPath, repoId, dependencyVersion);

        // 准备元数据包
        mdpkgPath = metadataProjectCoreService.getMdpkgPath(projPath);
        Utils.checkEmpty(mdpkgPath, "未找到元数据包，请先编译：" + projPath);
        createSrcDir(metadataTempDir);
        String destPath = metadataTempDir + File.separator + MavenUtils.RESOURCES_DIR + File.separator + new File(mdpkgPath).getName();
        try {
            fileServiceImp.fileCopy(mdpkgPath, destPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Model createSourceModel() {
        sourceModel = new Model();
        final GspProject gspProjectInfo = gspProjectCoreService.getGspProjectInfo(projPath);
        sourceModel.setGroupId(getGroupId(gspProjectInfo));
        sourceModel.setArtifactId(getArtifactID(gspProjectInfo) + "-api");
        sourceModel.setVersion(version);
        List<Dependency> dependencies = new ArrayList<>();
        final MetadataProject metadataProjInfo = metadataProjectCoreService.getMetadataProjInfo(projPath);
        if (metadataProjInfo.getMavenPackageRefs() != null && metadataProjInfo.getMavenPackageRefs().size() > 0) {
            metadataProjInfo.getMavenPackageRefs().forEach(mavenPackageRef -> {
                Dependency dependency = new Dependency();
                dependency.setGroupId(mavenPackageRef.getGroupId());
                dependency.setArtifactId(mavenPackageRef.getArtifactId());
                dependency.setVersion(mavenPackageRef.getVersion());
                dependencies.add(dependency);
            });
        }
        sourceModel.setDependencies(dependencies);
        return sourceModel;
    }

    private String getGroupId(GspProject gspProject) {
        String groupId;
        String prepareGroupId = gspProject.getProjectNameSpace().toLowerCase();
        String firstGroupId = "com.";
        if (!prepareGroupId.contains(".")) {
            return firstGroupId + prepareGroupId;
        }
        String[] subGroupId = prepareGroupId.split("\\.");
        groupId = firstGroupId + (subGroupId[0] + "." + subGroupId[1]).toLowerCase();
        return groupId;
    }

    private String getArtifactID(GspProject gspProject) {
        String appCode = gspProject.getAppCode().toLowerCase();
        String suCode = gspProject.getServiceUnitCode().toLowerCase();
        String boCode = gspProject.getMetadataProjectName().toLowerCase();
        if (boCode.startsWith("bo-")) {
            boCode = boCode.substring(boCode.indexOf("-") + 1);
        }
        String artifactId = String.format("%s-%s-%s", appCode, suCode, boCode);

        return artifactId;
    }

    private boolean createSrcDir(String mdpkgPath) {
        String resDir = mdpkgPath + File.separator + MavenUtils.RESOURCES_DIR;
        File resourceFile = new File(resDir);
        return resourceFile.mkdirs();
    }

    public void updateMetadataIndex(String mdpkgName, String mdpkgDir, String repoUrl, Model sourceModel,
        String processMode) {
        MetadataPackage metadataPackage = new MetadataCoreManager().getMetadataPackageInfo(mdpkgName, mdpkgDir);
        if (metadataPackage.getMetadataList() != null && metadataPackage.getMetadataList().size() > 0) {
            PackageWithMetadataInfoWithProcessMode packageWithMetadataInfoWithProcessMode = new PackageWithMetadataInfoWithProcessMode();
            packageWithMetadataInfoWithProcessMode.setMavenPackageGroupId(sourceModel.getGroupId());
            packageWithMetadataInfoWithProcessMode.setMavenPackageArtifactId(sourceModel.getArtifactId());
            packageWithMetadataInfoWithProcessMode.setMavenPackageVersion(sourceModel.getVersion());
            packageWithMetadataInfoWithProcessMode.setMavenPackageUrl(repoUrl);
            packageWithMetadataInfoWithProcessMode.setProcessMode(processMode);

            List<MetadataInfoInMavenWithProcessMode> metadatas = new ArrayList<>();
            for (GspMetadata metadata : metadataPackage.getMetadataList()) {
                MetadataInfoInMavenWithProcessMode tempMetadata = new MetadataInfoInMavenWithProcessMode();
                tempMetadata.setMetadataId(metadata.getHeader().getId());
                tempMetadata.setMetadataCode(metadata.getHeader().getCode());
                tempMetadata.setMetadataName(metadata.getHeader().getName());
                tempMetadata.setMetadataNamespace(metadata.getHeader().getNameSpace());
                tempMetadata.setMetadataType(metadata.getHeader().getType());
                tempMetadata.setMetadataIsTranslating(metadata.getHeader().getTranslating() ? "t" : "f");
                tempMetadata.setMdBizobjectId(metadata.getHeader().getBizObjectId());
                tempMetadata.setMetadataPackageCode(metadataPackage.getHeader().getName());
                tempMetadata.setMetadataPackageVersion(metadataPackage.getHeader().getVersion().getVersionString());
                tempMetadata.setMetadataLanguage(metadata.getHeader().getLanguage());
                tempMetadata.setMavenPackageGroupId(sourceModel.getGroupId());
                tempMetadata.setMavenPackageArtifactId(sourceModel.getArtifactId());
                tempMetadata.setMavenPackageVersion(sourceModel.getVersion());
                tempMetadata.setMavenPackageUrl(repoUrl);
                tempMetadata.setProcessMode(processMode);
                metadatas.add(tempMetadata);
            }

            packageWithMetadataInfoWithProcessMode.setMetadatas(metadatas);

            String indexServerUrl = IndexServerManager.getInstance().getIndexServerWithProcessModeUrl();
            try {
                restTemplate.postForObject(indexServerUrl, new HttpEntity<>(packageWithMetadataInfoWithProcessMode, new HttpHeaders()), boolean.class);
            } catch (Exception e) {
                if (e.getMessage().contains("404")) {
                    throw new RuntimeException("未更新索引服务器版本，无法推送解析型元数据。请联系管理员解决。");
                } else {
                    throw e;
                }
            }
        }
    }
}
